/*
 * Copyright (c) 2019. Baidu Inc. All Rights Reserved.
 */

package main

import (
	"encoding/json"
	"fmt"
	"strconv"

	"github.com/xuperchain/xuperchain/core/contractsdk/go/code"
	"github.com/xuperchain/xuperchain/core/contractsdk/go/driver"
)

type elecCert struct {
	User *User
}

// User TODO
type User struct {
   Owner     string
   UserFiles map[string]*UserFile
   BuisnessUserFiles map[string]*UserFile
}

// UserFile TODO
type UserFile struct {
   Timestamp int64
   Hashval   []byte
   Data      string
   BusinessId string
   ApplyNotarization string
   EntityName string
   FileHash   string
}

func newElecCert() *elecCert {
	return &elecCert{}
}

// func (e *elecCert) putFile(user string, filehash string, ts int64) *User {
// 	userFile := &UserFile{
// 		Timestamp: ts,
// 		Hashval:   []byte(filehash),
// 	}
//
// 	if e.User != nil {
// 		e.User.Owner = user
// 		e.User.UserFiles[filehash] = userFile
// 		return e.User
// 	}
//
// 	u := &User{
// 		Owner:     user,
// 		UserFiles: map[string]*UserFile{},
// 	}
// 	u.UserFiles[filehash] = userFile
//
// 	e.User = u
//
// 	return u
// }

func (e *elecCert) putFile(user string, filehash string, ts int64,data string,businessId string,applyNotarization string,entityName string) *User {
	userFile := &UserFile{
		Timestamp: ts,
		Hashval:   []byte(filehash),
        Data: data,
        BusinessId: businessId,
        ApplyNotarization: applyNotarization,
        EntityName: entityName,
        FileHash: filehash,
	}

	if e.User != nil {
		e.User.Owner = user
		e.User.UserFiles[filehash] = userFile
		e.User.BuisnessUserFiles[businessId] = userFile
		return e.User
	}

	u := &User{
		Owner:     user,
		UserFiles: map[string]*UserFile{},
		BuisnessUserFiles: map[string]*UserFile{},
	}
	u.UserFiles[filehash] = userFile
	u.BuisnessUserFiles[businessId] = userFile

	e.User = u

	return u
}

// func (e *elecCert) putFile(user string, filehash string, ts int64,data string,businessId string,applyNotarization string,entityName string) *User {
//    userFile := &UserFile{
//       Timestamp: ts,
//       Hashval:   []byte(filehash),
//       data: data,
//       businessId: businessId,
//       applyNotarization: applyNotarization,
//       entityName: entityName,
//       fileHash: filehash,
//    }
//
//    if e.User != nil {
//       e.User.Owner = user
//       e.User.UserFiles[filehash] = userFile
//       e.User.BuisnessUserFiles[businessId] = userFile
//       return e.User
//    }
//
//    u := &User{
//       Owner:     user,
//       UserFiles: map[string]*UserFile{},
//    }
//    u.UserFiles[filehash] = userFile
//    u.BuisnessUserFiles[businessId] = userFile
//
//    e.User = u
//
//    return u
// }

func (e *elecCert) getFile(user string, filehash string) (*UserFile, error) {
	if e.User != nil {
		if userFile, ok := e.User.UserFiles[filehash]; ok {
			return userFile, nil
		}
		return nil, fmt.Errorf("User's file:%v no exist", filehash)
	}

	return nil, fmt.Errorf("User:%v no exist", user)
}


func (e *elecCert) getFileByFileHash(user string, filehash string) (*UserFile, error) {
   if e.User != nil {
      if userFile, ok := e.User.UserFiles[filehash]; ok {
         return userFile, nil
      }
      return nil, fmt.Errorf("User's file:%v no exist", filehash)
   }

   return nil, fmt.Errorf("User:%v no exist", user)
}

func (e *elecCert) getFileByBusinessId(user string, businessId string) (*UserFile, error) {
   if e.User != nil {
      if userFile, ok := e.User.BuisnessUserFiles[businessId]; ok {
         return userFile, nil
      }
      return nil, fmt.Errorf("User's file:%v no exist", businessId)
   }

   return nil, fmt.Errorf("User:%v no exist", user)
}

func (e *elecCert) setContext(ctx code.Context, user string) {
	value, err := ctx.GetObject([]byte(user))
	if err != nil {
	} else {
		userStruc := &User{}
		err = json.Unmarshal(value, userStruc)
		if err != nil {
		}
		e.User = userStruc
	}
}

func (e *elecCert) Initialize(ctx code.Context) code.Response {
	user := string(ctx.Args()["owner"])
	if user == "" {
		return code.Errors("Missing key: owner")
	}

	e.setContext(ctx, user)

	return code.OK(nil)
}

func (e *elecCert) Save(ctx code.Context) code.Response {
	user := string(ctx.Args()["owner"])
	if user == "" {
		return code.Errors("Missing key: owner")
	}
	filehash := string(ctx.Args()["filehash"])
	if filehash == "" {
		return code.Errors("Missing key: filehash")
	}
	ts := string(ctx.Args()["timestamp"])
	if ts == "" {
		return code.Errors("Missing key: timestamp")
	}

	data := string(ctx.Args()["data"])
    if data == "" {
       return code.Errors("Missing key: data")
    }

    businessId := string(ctx.Args()["businessId"])
    if businessId == "" {
       return code.Errors("Missing key: businessId")
    }

    applyNotarization := string(ctx.Args()["applyNotarization"])
    if applyNotarization == "" {
        return code.Errors("Missing key: applyNotarization")
    }

    entityName := string(ctx.Args()["entityName"])
    if entityName == "" {
         return code.Errors("Missing key: entityName")
    }

	e.setContext(ctx, user)
	tsInt, _ := strconv.ParseInt(ts, 10, 64)
// 	userStruc := e.putFile(user, filehash, tsInt)

    userStruc := e.putFile(user, filehash, tsInt,data,businessId,applyNotarization,entityName)

	userJSON, _ := json.Marshal(userStruc)

	err := ctx.PutObject([]byte(user), userJSON)
	if err != nil {
		return code.Errors("Invoke method PutObject error")
	}

	return code.OK(userJSON)
}

func (e *elecCert) Query(ctx code.Context) code.Response {
	user := string(ctx.Args()["owner"])
	if user == "" {
		return code.Errors("Missing key: owner")
	}

	filehash := string(ctx.Args()["filehash"])
    businessId := string(ctx.Args()["businessId"])

    //二者不能同时为空
   if filehash == "" {
       if businessId == "" {
            return code.Errors("Missing key:  filehash or businessId")
        }
   }

	e.setContext(ctx, user)

    //如果filehash为空 则按照businessId查询 否则按照filehash查询
    if filehash == "" {
        userFile, err := e.getFileByBusinessId(user,businessId)

        if err != nil {
            return code.Errors("Query not exist")
        }

        userFileJSON, _ := json.Marshal(userFile)
        return code.OK(userFileJSON)

    }else{
        userFile, err := e.getFileByFileHash(user,filehash)

        if err != nil {
            return code.Errors("Query not exist")
        }

        userFileJSON, _ := json.Marshal(userFile)
        return code.OK(userFileJSON)
    }
}

func main() {
	driver.Serve(newElecCert())
}
